const express = require('express');
const cors = require('cors');
const app = express();
const port = 8888;
const mysql = require('mysql')
const { v4: uuidv4 } = require('uuid');
const crypto = require('crypto');
/**
 * @description 对用户密码进行哈希加密
 * @param {*} password 
 * @returns salt , hashedPassword
 */
function hashPassword(password) {
    // 生成一个随机的盐值
    const salt = crypto.randomBytes(16).toString('hex');
    // 使用 SHA-256 算法对密码和盐值进行哈希
    const hashedPassword = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha256').toString('hex');
    return {
        salt,
        hashedPassword
    };
}
/**
 * @param {*} password 用户输入的密码
 * @param {*} salt 盐
 * @param {*} hashedPassword 密码哈希
 * @returns boolean true 表示密码验证成功，false 表示密码验证失败
 * @author long
 */
function verifyPassword(password, salt, hashedPassword) {
    // 使用相同的盐值和哈希算法对用户提供的密码进行哈希
    const hashedPasswordAttempt = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha256').toString('hex');
    // 比较哈希后的密码值是否与数据库中存储的哈希值相同
    return hashedPassword === hashedPasswordAttempt;
}

// 建立与mysql的链接
const db = mysql.createPool({
    host: '127.0.0.1',//数据库地址
    user: 'admin',//数据库用户名
    password: 'admin',//数据库密码
    database: 'db1'//链接的数据库名称
})
app.use(express.json());
app.use(cors())
app.use(express.urlencoded({ extended: true }))

/**
 * @description 监听addUser请求 接收四个参数username password email telphone均为必填字段 默认字段为add_date添加日期
 * @author long
 */
app.post('/v2/addUser', (req, res, next) => {
    const params = req.body;
    console.log('params:', params);

    // 判断是否有空值
    for (let key in params) {
        if (params.hasOwnProperty(key)) {
            if (params[key] === undefined || params[key] === null || params[key] === '') {
                return next(Error(`${key} is undefined, null, or an empty string.`));
            }
        }
    }
    // 使用正则表达式校验用户名：5~16个大小写字母和汉字，不含符号
    const usernameRegex = /^[a-zA-Z0-9]{5,16}$/;
    // 使用正则表达式校验手机号：11位中国大陆号码
    const telphoneRegex = /^1[3-9]\d{9}$/;

    // 校验username字段
    if (!usernameRegex.test(params.username)) {
        // 生成一个错误对象，并将这个错误对象传递给下一个中间件或全局错误处理中间件
        return next(new Error('请输入正确的用户名,用户名为5~16个大小写字母和数字，不含符号。'));
    }
    // 校验telphone字段
    if (!telphoneRegex.test(params.telphone)) {
        return next(new Error('请输入11位中国大陆手机号码。'));
    }

    //使用crypto对密码进行加密
    const password = params.password;
    const { salt, hashedPassword } = hashPassword(password);
    // console.log('Salt:', salt);
    // console.log('Hashed Password:', hashedPassword);
    // 验证密码
    // const isPasswordCorrect = verifyPassword(password, salt, hashedPassword);

    // 生成 UUID
    const uuid = uuidv4();
    // 插入数据 使用变量插值 防止sql注入攻击
    const sql = 'insert into user(uuid,username,password,email,telphone,add_date) values(?,?,?,?,?,?)';
    var date = new Date();
    // 格式化注册时间
    var dateTimeFormat = date.getFullYear() + '-' + ('0' + (date.getMonth() + 1)).slice(-2) + '-' + ('0' + date.getDate()).slice(-2) + ' ' + ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + ':' + ('0' + date.getSeconds()).slice(-2);
    db.query(sql, [uuid, params.username, hashedPassword, params.email, params.telphone, dateTimeFormat], (err, result) => {
        if (err) {
            return next(new Error(err.message));
        } else {
            res.send({ status: 'success', code: 200, msg: '插入成功', req: params });
        }
    });
});
/**
 * @description 获取所有用户信息
 * @author long
 */
app.get('/v2/getUserList', (req, res, next) => {
    const sql = 'select * from user';
    db.query(sql, (err, result) => {
        if (err) {
            return next(new Error(err.message));
        } else {
            // 数据脱敏 删除敏感字段
            result.forEach(item => {
                delete item.password;
            });
            res.send({ status: 'success', code: 200, msg: '查询成功', data: result });
        }
    });
})
/**
 * @description 根据uuid删除用户
 * @param {*} uuid 用户唯一标识
 * @author long
 */
app.get('/v2/deleteUser', (req, res, next) => {
    const params = req.query;
    const sql = 'delete from user where uuid=?';
    db.query(sql, [params.uuid], (err, result) => {
        if (err) {
            return next(new Error(err.message));
        } else {
            res.send({ status: 'success', code: 200, msg: '删除成功', data: result });
        }
    });
})
/**
 * @description 根据uuid更新用户信息
 * @param {*} uuid 用户唯一标识
 * @author long
 */
app.post('/v2/updateUser', (req, res, next) => {
    const params = req.body;
    if (params.uuid) {
        delete params.password;
    }
    for (let key in params) {
        if (params.hasOwnProperty(key)) {
            if (params[key] === undefined || params[key] === null || params[key] === '') {
                return next(Error(`${key} is undefined, null, or an empty string.`));
            }
        }
    }
    // 使用正则表达式校验用户名：5~16个大小写字母和汉字，不含符号
    const usernameRegex = /^[a-zA-Z0-9]{5,16}$/;
    // 使用正则表达式校验手机号：11位中国大陆号码
    const telphoneRegex = /^1[3-9]\d{9}$/;

    // 校验username字段
    if (!usernameRegex.test(params.username)) {
        // 生成一个错误对象，并将这个错误对象传递给下一个中间件或全局错误处理中间件
        return next(new Error('请输入正确的用户名,用户名为5~16个大小写字母和数字，不含符号。'));
    }
    // 校验telphone字段
    if (!telphoneRegex.test(params.telphone)) {
        return next(new Error('请输入11位中国大陆手机号码。'));
    }
    const sql = 'update user set username=?,email=?,telphone=? where uuid=?';
    db.query(sql, [params.username, params.email, params.telphone, params.uuid], (err, result) => {
        if (err) {
            return next(new Error(err.message));
        } else {
            res.send({ status: 'success', code: 200, msg: '更新成功', data: result });
        }
    });
})


// 定义一个错误中间件来捕获全局的错误 它有四个参数err,req,res,next  错误中间件必须在所有路由之后定义
app.use((err, req, res, next) => {
    res.send({ status: 'error', code: 500, msg: 'Error:' + err.message, req: req.body });
    next()
})
app.listen(port, () => {
    console.log(`server is running on port ${port}`);
});
